import { SendController } from './lib/sendController'                       //发送器
import { ReceiverController } from './lib/receiverController'               //接收器
import Storage from './lib/storage';
import Heart from "./lib/heart";                                            //心跳对象
import TalkObject from './lib/talkObject';                                  //会话对象
import FriendObject from './lib/friendObject';                              //好友申请
import Controller from './lib/controller';
let config = sessionStorage.getItem("config");                              //域名，端口 config 
console.log(config);
config = config ? JSON.parse(config) : '';
const _getSo = Symbol("_getSo"),
    _getHttp = Symbol('_getHttp'),
    _login = Symbol('_login'),
    _setTime = Symbol('_setTime');
export class Socket {
    static instance = null;                                                 // 实例
    static v = 24;
    static port = 2345;
    #loginData = {
        userData: { member_id: 0 },
    }
    #userLoginStatus = {                                                    //用户登录状态数据
        leaveType: 0,              //0.初始化  1 .被踢下线   2. socket断开 
        isOnLine: false,           //true在线  ,  false 离线
        userSelect: 0,             //0.没有选择 ，1.继续连接  2.不连接
        timeOff: '',               //定时器开关
    }
    constructor() {
        if (!Socket.instance) {
            Socket.instance = this;
            Socket.instance.so = null;
            //页面刷新载入本地缓存
            this.#loginData = { ...this.#loginData, ...config };
            console.log(this.#loginData.h_url);
            let userData = sessionStorage.getItem('userData');
            if (userData) {
                userData = JSON.parse(userData);
                this.#loginData.userData = { ...userData }
            }
            //实例化发送器和接受器、会话对象、心跳
            this.sendController = new SendController(this);                      //socket 成功连接时，实例化发送器实例
            this.receiverController = new ReceiverController(this);              //接收器
            this.talkObject = new TalkObject();
            this.controller = new Controller(this, this.#loginData);
            this.friendObject = new FriendObject();
            this.heart = new Heart();        
            this.storage = new Storage(this);                                    
            let loginData = sessionStorage.getItem('loginData');                 //当本地token,key 进行快速登录
            if (loginData) {
                loginData = JSON.parse(loginData);
                const { token, key } = loginData;
                if (token && key) { Socket.instance[_login]('', '', key, token); }
            }
            this.UserTalkList = [];
            // new Error("版本:" + Socket.v).message
            console.log("版本:" + Socket.v)
            // throw "版本:" + Socket.v;
        }
        return Socket.instance;
    }
    /*socket实例*/
    setConfig(option) {
        const required = ['h_url', 'a_url', 'e_url', 'port', 'sertype', 'onLoginSuccess', 'onCloseCallback'];     //必填字段
        const falg = required.find(key => {                                                                       //必填字段验证
            if (!option[key] && key) { return key }
        })
        if (typeof option.onLoginSuccess != "function") { alert("onLoginSuccess 必需为函数！"); return }
        if (falg) { alert(falg + "字段缺失!"); return {} }
        this.#loginData = { ...this.#loginData, ...option };                                                      //赋值
        config = option;
        this.talkObject.initSessionStorage(this.#loginData);                                                           //本地存储 config            //登录
    }
    /*用户快速连接*/
    quickConnect(key, token) {
        /*
        1.初始化member_id。
        2.设置port。
        */
        for (let i in arguments) {
            if (arguments[i] == undefined || arguments[i] == '') {
                console.log("quickConnect,第" + i + "个参数不能为空！");
                return
            }
        }
        this.#loginData.userData.member_id = 0;
        this.#loginData.key = key;
        this.#loginData.token = token;
        this[_login]('', '', key, token);
        // this.#loginData.userData.port = port ? port : this.#loginData.userData.port;                            //设置端口
    }
    /*本地存储清空*/
    clearStorage() {
        sessionStorage.clear();
        localStorage.clear();
    }
    /*用户操作方法入口*/
    action(fnName, params, callback, failCallback) {
        return this.controller.action(fnName, params, callback, failCallback)
    }
    /*(测试)断开连接*/
    loginOut() {
        this.so.close();
        this.so = null;
    }
    /*判断登录状态*/
    readyStateLogin(onSuccess) {
        let i = setInterval(() => {
            if (this.#userLoginStatus.isOnLine) {
                clearInterval(i);
                onSuccess();
            }
        }, 1000);
    }
    /*登录成功后执行*/
    loginSuccess(res) {
        let member_id = res.data.userData.member_id,
            loginData = sessionStorage.getItem("loginData");
        loginData = JSON.parse(loginData);
        let { token, key } = loginData;
        //自动重连属性
        this.#userLoginStatus.isOnLine = true;                                              // 改变登录状态
        this.#userLoginStatus.userSelect = 0;                                               // 初始化用户选择
        this.#userLoginStatus.leaveType = 0;
        //用户基本属性  
        this.#loginData.userData.token = token;
        this.#loginData.userData.key = key;
        this.storage.setProperty(this.#loginData.userData);
        this[_setTime]();                                                                   // 检测断线
        this.controller.setProperty(member_id, token, key, this.#loginData.h_url, this.#loginData.a_url, this.#loginData.e_url)
        res.data.msgList.forEach(item => { this.receiverController.receiverMsg(item) });    // 执行离线消息执行一遍
        this.#loginData.onLoginSuccess && this.#loginData.onLoginSuccess({                  // 登录成功，用户的回调函数          
            userData: res.data.userData,
            token,
        })
    }
    /*登录*/
    [_login](username, password, key, token) {
        // if (!username || !password) { alert("账号密码不能为空！"); return }
        if (!config || !config.a_url) {
            // console.log("config为空！");
            alert("config为空！")
            // console.log(this.#loginData)
            return { code: 301, data: "config 参数缺失！" }
        }
        // so 已经连接
        if (this.so && this.so.readyState == 1) {
            console.log("不要重复登录！");
            return { code: 301, data: "不要重复登录！" }
        }
        var that = this;
        that[_getHttp](
            that.#loginData['h_url'] + "/getLoginKey",
            { token, port: that.#loginData.port },
            function (data) {
                if (data.code == 200) {
                    var loginKey = data.data.loginKey;
                    var isForceLogin = data.data.isNeedForceLogin;
                    let url = "ws://" + that.#loginData['e_url'] + ":" + Socket.port;                   //url='ws://e.com:2345';
                    sessionStorage.setItem('loginData', JSON.stringify({ key, token }));
                    that[_getSo](url, key, loginKey, token, isForceLogin, that.#loginData.sertype);
                }
            }
        );
    }
    /*socket连接 ，so监听事件*/
    [_getSo](url, key, loginKey, token, isForceLogin, sertype, callback, failCallback) {
        for (let i in arguments) {
            if (arguments[i] == undefined || arguments[i] == '') {
                console.log("getSo,第" + i + "个参数不能为空！");
                return
            }
        }
        const that = this;
        console.log(this.so);
        if (this.so == null) {
            this.so = new WebSocket(url);
            this.so.onerror = () => { console.log("so连接失败！") };
            /*socket成功连接
            1.实例化发送器 
            2.实例化接受器
            3.发送一条login类型消息，获取用户信息
            */
            that.so.onopen = function () {
                if (that.so && that.so.readyState == 1) {
                    that.receiverController.so = that.sendController.so = that.so;
                    const msg = that.sendController.pushMessage("login", { key, loginKey, token, sertype, isForceLogin }, that.#loginData.userData.member_id, (data) => {
                        if (data.body.code == 200) { callback && callback(data.body) } else { failCallback && failCallback(data.body); }
                    });
                    if (msg.code != 200) {
                        alert("消息创建失败！");
                        return { code: 301, data: '消息创建失败！' }
                    }
                    that.sendController.sendMessage(msg.data.data.head.clientMsgId);
                }
            };
            /*webSocket接收消息监听，接收服务器推送过来的信息，返回的数据给msg，然后进行显示
            1.判断消息类型(服务器回执，服务器消息)
            2.当服务器返回login类型消息时，表示用户被踢下线，改变userLoginStatus 连接状态，用户选择状态。
            3.获取用户的选择，根据用户的选择进行操作
            4.当用户同意连接时，改变userLoginStatus断线状态、断线原因。
            5.当用户拒绝连接时，清空userLoginStatus定时器(循环检测用户状态的函数)、本地会话存储。不再连接。 
            */
            this.so.onmessage = function (msg) {
                var data = JSON.parse(msg.data);
                if (data.head.ms == 1) {                            //服务端发送的数据
                    that.receiverController.receiverMsg(data);
                } else {
                    that.sendController.getServerReceiptMsg(data);   //回执消息的处理  
                }
            };
            /*socket断开
            1.根据断线类型进行操作
            2.当socket断开类型不属于被踢下线时，将断线类型改变为 2 (socket断开)
            3.触发试图层断开连接的回调函数
            4.停止心跳检测
            */
            this.so.onclose = function () {
                // console.log("离线!");
                if (that.#userLoginStatus.leaveType != 1) { that.#userLoginStatus.leaveType = 2; that.so = null; }
                that.#userLoginStatus.isOnLine = false;
                that.#loginData.onConnectClose ? that.#loginData.onConnectClose() : '';               //socket断开回调 
                that.heart.stop();                                                                    //停止心跳检测
                that.friendObject.clear();
                that.talkObject.clear();
            };
        }
    }
    /*请求*/
    [_getHttp](url, params, callback) {
        for (let i in arguments) {
            if (arguments[i] == undefined || arguments[i] == '') {
                alert("getHttp参数，第 " + i + "个参数不能为空！");
                return
            }
        }
        var xmlpost = new XMLHttpRequest();
        xmlpost.open("post", url, true);
        var postData = [];
        if (params) {
            for (let i in params) {
                postData.push(i + "=" + params[i]);
            }
            postData = postData.join("&");
        }
        xmlpost.send(postData);
        xmlpost.onreadystatechange = function () {
            if (xmlpost.readyState == 4) {
                if (xmlpost.status == 200) {
                    var data = JSON.parse(xmlpost.responseText);
                    callback(data);
                    if (data.code != 200) {
                        console.log("请求出错", data.data);
                    }
                }
            }
        };
    }
    /*定时检测so是否断开连接*/
    [_setTime]() {
        const controller = this.#userLoginStatus;
        if (controller.timeOff) { return }                                                                   //防止重复开启定时器
        controller.timeOff = setInterval(() => {
            if (controller.isOnLine) { return }                                                               //在线不操作或者初始化                       
            if (controller.leaveType == 1) {                                                                 //被踢下线
                if (controller.userSelect == 1) {
                    this.so = null;
                    this[_login]('', '', this.#loginData.userData.key, this.#loginData.userData.token);
                }
                else if (controller.userSelect == 2) { clearInterval(controller.timeOff); sessionStorage.clear(); }
                return { code: 301, data: '断线提示：强制登出!' }
            }
            if (controller.leaveType === 0) { return }
            clearInterval(controller.timeOff);
            controller.timeOff = '';
            const res = confirm("你已经断开连接，你需要重新连接吗？");
            if (res) {
                this[_login]('', '', this.#loginData.userData.key, this.#loginData.userData.token)
                this[_setTime]();
            } else {
                sessionStorage.clear();
            }
        }, 5000);
    }
    /*强制登出*/
    _logOut() {
        var that = this;
        that.#userLoginStatus.isOnLine = false;
        that.#userLoginStatus.userSelect = 0;
        that.#userLoginStatus.leaveType = 1;
        that.so = null;
        //3.获取用户的选择，根据用户的选择进行操作
        const res = that.#loginData.onCloseCallback();
        if (res) {
            //4.当用户同意连接时，改变userLoginStatus断线状态、断线原因。
            that.#userLoginStatus.userSelect = 1
        } else {
            //5.当用户拒绝连接时，清空userLoginStatus定时器(循环检测用户状态的函数)、本地会话存储。不再连接。 
            that.#userLoginStatus.userSelect = 2;
            sessionStorage.clear();
            clearInterval(that.#userLoginStatus.timeOff);
            that.#userLoginStatus.timeOff = '';
        }
    }
}